package com.easytouch.core;

import com.easytouch.core.ftp.FTP;
import com.easytouch.core.ftp.FTPClient;
import com.easytouch.core.ftp.FTPReply;
import com.easytouch.core.utils.Log;
import com.easytouch.core.utils.SDCardTools;
import com.easytouch.core.utils.SystemTools;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;

import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.os.SystemClock;

public class UpdateThread extends Thread {
    private static final String UPDATER_NEW = "com.easytouch.remoteupdater";

    private String SERVER_IP = "easytouch-pay.cn"; //120.27.28.226 //easytouch-pay.cn //test10.easytouch-pay.net
    private String SERVER_PORT = "6001";
    private long startTime;
    private String mac = ""; // 机器号，从文件中读取
    private String VERSION = ""; // 当前版本，从文件中读取

    private FTPClient ftpClient = new FTPClient();
    private String ftpHost = "easytouch-pay.cn"; //120.27.28.226
    private int ftpPort = 21;
    private String ftpUserName = "user";
    private String ftpPassword = "111";

    private ArrayList<String> mApkFileList = new ArrayList<>();

    public Log mLogger = new Log("UpdateThread.txt");

    @Override
    public void run() {
        super.run();
        if(!loadConfig())
        {
            mLogger.i("未开启更新远程升级服务");
            return;
        }
        waitSeconds(5);
        do
        {
            startTime = System.currentTimeMillis();
            //检查是否有更新
            String url = getUpdateInfo();
            if(url == null || "".equals(url) || url.length() <= 5)
            {
                waitForNextTime();
                continue;
            }
            //下载
            String mUrlPath = url.substring(5);
            File downloadFile = null;
            try {
                downloadFile = getDataSource(mUrlPath);
            } catch (Exception e1) {
                mLogger.i("it occur Exception when download file. the cause is : " + e1.getMessage());
                waitSeconds(60);
                waitForNextTime();
                continue;
            }
            if(downloadFile == null)
            {
                waitSeconds(60);
                waitForNextTime();
                continue;
            }
            //解压
            //String zipFilePath = downloadFile.getAbsolutePath();
            //String fileName = zipFilePath.substring(zipFilePath.lastIndexOf("/") + 1, zipFilePath.lastIndexOf("."));
            boolean unzip = false;
            String updateFolder = Configure.path + "/update";
            mApkFileList.clear();
            try {
                unzip = unZipFolder(downloadFile.getAbsolutePath(), updateFolder);
            } catch (Exception e) {
                mLogger.i("unzip file occur Exception. the cause is : " + e.getMessage());
                waitSeconds(60);
                waitForNextTime();
                continue;
            }
            if(!unzip)
            {
                waitSeconds(60);
                waitForNextTime();
                continue;
            }
            //杀掉进程
            SystemTools.killApp(UPDATER_NEW);
            waitSeconds(5);
            //安装
            for (String apk: mApkFileList) {
                mLogger.i("install app:" + apk);
                File apkFile = new File(apk);
                if(apkFile.exists())
                {
                    int result = SystemTools.installApp(apkFile);
                    if(result < 0)
                    {
                        mLogger.e("apk file install failed:" + apk);
                        apkFile.delete();
                    }
                    else
                    {
                        apkFile.delete();
                    }
                }
            }
            mApkFileList.clear();
            //拷贝资源目录和文件
            String updateName = "";
            File updateFile = new File(updateFolder);
            File[] currentFiles = updateFile.listFiles();
            for (File file: currentFiles) {
                String name = file.getName();
                if(file.isDirectory() && !".".equals(name) && !"..".equals(name))
                {
                    updateName = name;
                    break;
                }
            }
            int copyResult = copy(updateFolder + "/" + updateName, SDCardTools.getSDCardPath() + "/Android/data");
            if(copyResult < 0)
            {
                mLogger.e("copy files failed");
                cleanUp(updateFolder);
                waitSeconds(60);
                waitForNextTime();
                continue;
            }
            cleanUp(updateFolder);
            //运行app
            Intent intent = new Intent();
            intent.setComponent(new ComponentName(UPDATER_NEW, UPDATER_NEW + ".activity.MainActivity"));
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            try {
                if(Configure.context != null)
                    Configure.context.startActivity(intent);
            }
            catch (ActivityNotFoundException e)
            {
                mLogger.e("ActivityNotFoundException:" + e.getMessage());
            }
            //更新本地版本信息
            try {
                updateLocal(url.substring(0, 4));
            } catch (Exception e) {
                mLogger.i("it occur Exception when update local version. the cause is : " + e.getMessage());
                waitSeconds(60);
                waitForNextTime();
                continue;
            }
            //更新服务器版本信息
            try {
                updateServer();
            } catch (Exception e) {
                mLogger.i("it occur Exception when update server version. the cause is : " + e.getMessage());
                waitSeconds(60);
                waitForNextTime();
                continue;
            }
            waitForNextTime();
        }while(true);
    }

    private String getInstalledAppVersion(Context ctx, String packageName)
    {
        String version = "";
        List<PackageInfo> packages = ctx.getPackageManager().getInstalledPackages(0);
        for (PackageInfo info: packages) {
            if(packageName.equals(info.packageName)) {
                version = info.versionName;
                break;
            }
        }
        return version;
    }

    private void updateServer() throws Exception {
        // 重新读取配置文件中的版本号
        String newVersionFromFile = readVersion();
        // 获取软件版本号
        String apkVersion = getInstalledAppVersion(Configure.context, UPDATER_NEW);

        StringBuilder builder = new StringBuilder();
        builder.append("02-");
        builder.append(apkVersion);
        for (int i = builder.length(); i < 29; i++) {
            builder.append("0");
        }

        Socket socket = new Socket();
        OutputStream out = null;
        InputStream in = null;
        InetSocketAddress address = new InetSocketAddress(SERVER_IP,
                Integer.parseInt(SERVER_PORT));
        String sendData;
        try {
            socket.connect(address, 15000);
            socket.setKeepAlive(true);
            out = socket.getOutputStream();
            in = socket.getInputStream();
            sendData = builder.toString();
            String finalData = "92" + mac + newVersionFromFile + 4 + 0 + sendData + 2;
            out.write(finalData.getBytes());
            out.flush();
            String result = read(in, 2); // 上传版本信息成功后会服务器会返回数据
            mLogger.i("data sended is : " + finalData);
            if (result == null) {
                updateServer();
            }
        } catch (IOException e) {
            //updateServer(); // 发生异常重传
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    private void updateLocal(String newVersion){
        Configure.setConfigData(Configure.UPDATE_VERSION, newVersion);
    }

    /**
     * 删除指定目录下的全部文件和目录，目录本身不删除
     * @param pCleanFolder 要清理的目录
     */
    private void cleanUp(final String pCleanFolder)
    {
        File folder = new File(pCleanFolder);
        if(!folder.exists())
            return;
        if(folder.isFile())
        {
            folder.delete();
            return;
        }
        File[] files = folder.listFiles();
        for (File file: files) {
            if(file.isFile())
            {
                file.delete();
            }
            else if(file.isDirectory())
            {
                String name = file.getName();
                if(!".".equals(name) && !"..".equals(name))
                {
                    cleanUp(file.getAbsolutePath());
                }
                file.delete();
            }
        }
    }

    /**
     * 拷贝文件夹下所有的东西
     *
     * @param fromFile
     * @param toFile
     * @return 0 代表成功 -1 代表失败
     */
    private int copy(String fromFile, String toFile) {
        // 要复制的文件目录
        File[] currentFiles;
        File root = new File(fromFile);
        // 如同判断SD卡是否存在或者文件是否存在
        // 如果不存在则 return出去
        if (!root.exists()) {
            return -1;
        }
        // 如果存在则获取当前目录下的全部文件 填充数组
        currentFiles = root.listFiles();

        // 目标目录
        File targetDir = new File(toFile);
        // 创建目录
        if (!targetDir.exists()) {
            //mLogger.i("dir does not exist");
            targetDir.mkdirs();
            //mLogger.i("make dir result : " + targetDir.exists());
        }
        // 遍历要复制该目录下的全部文件
        //mLogger.i("file count = " + currentFiles.length);
        for (int i = 0; i < currentFiles.length; i++) {
            if (currentFiles[i].isDirectory())// 如果当前项为子目录 进行递归
            {
//					mLogger.i("\r\n");
//					mLogger.i("文件夹 ：name = " + currentFiles[i].getName()
//							+ "\r\n fromPath = " + currentFiles[i].getPath()
//							+ "/\r\n destPath = " + toFile + "/"
//							+ currentFiles[i].getName() + "/");
                copy(currentFiles[i].getPath() + "/", toFile + "/"
                        + currentFiles[i].getName());

            } else// 如果当前项为文件则进行文件拷贝
            {
//					mLogger.i("文件：name = " + currentFiles[i].getName()
//							+ "\r\n fromPath = " + currentFiles[i].getPath()
//							+ "\r\n destPath = " + toFile + "/"
//							+ currentFiles[i].getName());
                CopyFile(currentFiles[i].getPath(), toFile + "/"
                        + currentFiles[i].getName());
            }
        }
        return 0;
    }

    /**
     * 拷贝文件
     *
     * @param fromFile
     * @param toFile
     * @return 0 代表成功 -1 代表失败 -- 抛异常
     */
    private int CopyFile(String fromFile, String toFile) {

        InputStream in = null;
        BufferedReader reader = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(fromFile);
            // reader = new BufferedReader(new InputStreamReader(in));
            out = new FileOutputStream(toFile);
            // BufferedWriter writer = new BufferedWriter(new
            // OutputStreamWriter(out));
            // String line = "";
            int len = -1;
            byte[] buffer = new byte[1024 * 4];
            long start = System.currentTimeMillis();
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
                // out.write(line.getBytes());
                // writer.write(line);
            }
            long end = System.currentTimeMillis();
//				mLogger.i("cast time : " + (end - start) + "s");
            return 0;

        } catch (Exception ex) {
            return -1;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private boolean unZipFolder(String zipFileString, String outPathString) throws FileNotFoundException, IOException {
        File zipFile = new File(zipFileString);
        if (!zipFile.exists()) {
            mLogger.i("unzip failed file no exists " + zipFileString);
            return false;
        }

        File desDir = new File(outPathString);
        if (!desDir.exists())
            desDir.mkdirs();

        BufferedInputStream bi;
        ZipFile zf = new ZipFile(zipFile, "UTF-8");
        Enumeration<?> e = zf.getEntries();
        while (e.hasMoreElements()) {
            ZipEntry ze2 = (ZipEntry) e.nextElement();
            String entryName = ze2.getName();
            String path = outPathString + "/" + entryName;

            mLogger.i("entryName = " + entryName);

            if (ze2.isDirectory()) {
                // mLogger.i("正在创建解压目录 - " + entryName);
                File decompressDirFile = new File(path);
                if (!decompressDirFile.exists()) {
                    decompressDirFile.mkdirs();
                }
            } else {
                String fileDir = path.substring(0, path.lastIndexOf("/"));
                File fileDirFile = new File(fileDir);
                if (!fileDirFile.exists()) {
                    fileDirFile.mkdirs();
                }
                if(path.endsWith(".apk")) //保存所有apk文件路径
                {
                    mApkFileList.add(path);
                }
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path));
                bi = new BufferedInputStream(zf.getInputStream(ze2));
                byte[] readContent = new byte[1024];
                int readCount = bi.read(readContent);
                while (readCount != -1) {
                    bos.write(readContent, 0, readCount);
                    readCount = bi.read(readContent);
                }
                bos.close();
            }
        }
        zf.close();
        mLogger.i("unzip success! " + zipFileString);
        return true;
    }

    private File getDataSource(String strPath) {
        // ftp://etftp:yichu123@120.27.28.226/update/VendingMachine_50Inch_Fortune_Portrait2.zip
        File myTempFile = null;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            /* 创建临时文件 */
            String fileEx = strPath.substring(strPath.lastIndexOf(".") + 1,
                    strPath.length());
            String fileNa = strPath.substring(strPath.lastIndexOf("/") + 1,
                    strPath.lastIndexOf("."));

            myTempFile = new File(SDCardTools.getSDCardPath() + "/" + fileNa
                    + "." + fileEx);

            if (myTempFile.exists())
                myTempFile.delete();
            myTempFile.createNewFile();

            String url = strPath;
            try {
                url = url.substring(0, url.lastIndexOf('/') + 1)
                        + URLEncoder.encode(
                        url.substring(url.lastIndexOf('/') + 1),
                        "UTF-8");
                url = url.replaceAll("\\+", "%20");
            } catch (UnsupportedEncodingException e) {
            }

            // ftp://user:111@182.92.226.124 ftp的字符串截取
            String temp = strPath.substring(6);
            int hostIndex = temp.indexOf("@");
            ftpPassword = temp.substring(0, hostIndex);
            ftpUserName = ftpPassword.substring(0, ftpPassword.indexOf(":"));
            ftpPassword = ftpPassword.substring(ftpUserName.length() + 1);
            ftpHost = temp.substring(hostIndex + 1);
            int pathIndex = ftpHost.indexOf("/");
            String pathString = ftpHost.substring(pathIndex);
            ftpHost = ftpHost.substring(0, pathIndex);
            int portIndex = ftpHost.indexOf(":");
            if (portIndex != -1) {
                ftpPort = Integer.parseInt(ftpHost.substring(portIndex + 1));
                ftpHost = ftpHost.substring(0, portIndex);
            } else {
                ftpPort = 21;
            }
            mLogger.i("getDataSource. ftp：" + ftpUserName + " " + ftpPassword
                    + " " + ftpHost + " " + ftpPort);
            if (!connect()) {
                mLogger.i("fail to connect ftp server：" + ftpHost);
                connect(); // 尝试重新连接
                return null;
            }

            // mLogger.i("getDataSource 003");
            // 设置被动模式
            ftpClient.enterLocalPassiveMode();
            // 设置以二进制方式传输
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            long localSize = myTempFile.length();
            long lRemoteSize = pathString.length();

            // mLogger.i("getDataSource 003");
            fos = new FileOutputStream(myTempFile, true);
            ftpClient.setRestartOffset(localSize);
            is = ftpClient.retrieveFileStream(new String(pathString
                    .getBytes("GBK"), "iso-8859-1"));
            byte buf[] = new byte[4096];
            // mLogger.i("getDataSource 003");

            long start = System.currentTimeMillis();
            do {
                if (is != null) {
                    int numread = is.read(buf);
                    if (numread <= 0) {
                        break;
                    }
                    fos.write(buf, 0, numread);
                    fos.flush();
                }
            } while (true);
            long end = System.currentTimeMillis();
            mLogger.i("Downlaod finished. cast time : " + (end - start) / 1000
                    + "s");
            mLogger.i("file downloaded size is : " + myTempFile.length() + " " + myTempFile.getAbsolutePath());
            return myTempFile;
        } catch (MalformedURLException e) {
            mLogger.i("Downlaod MalformedURLException:" + strPath);
        } catch (FileNotFoundException e) {
            mLogger.i("Downlaod FileNotFoundException:" + e.getMessage());
        } catch (IOException e) {
            mLogger.i("Downlaod IOException:" + e.getMessage());
            //getDataSource(strPath);
        } finally {
            try {
                if (fos != null)
                    fos.close();
                if (is != null)
                    is.close();
            } catch (IOException e) {
            }
        }
        return null;
    }

    public boolean connect() throws IOException {
        ftpClient.connect(ftpHost, ftpPort);
        ftpClient.setControlEncoding("GBK");
        if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {

            if (ftpClient.login(ftpUserName, ftpPassword)) {

                return true;
            }
        }
        disconnect();
        return false;
    }

    private void disconnect() {
        if (ftpClient.isConnected()) {
            try {
                ftpClient.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void waitForNextTime()
    {
        int t;
        String time = Configure.getConfigData(Configure.UPDATE_TIME);
        if(time == null && "".equals(time))
        {
            t = 15;
        }
        else
        {
            try {
                t = Integer.parseInt(time);
            }
            catch (NumberFormatException e)
            {
                t = 15;
            }
        }
        long endTime = System.currentTimeMillis();
        int totalTime = t * 60 * 1000;
        if (endTime - startTime <= totalTime) { // 每隔t分钟查询一次
            SystemClock.sleep(totalTime - (endTime - startTime));
        }
    }

    private String getUpdateInfo()
    {
        Socket socket = null;
        InputStream in;
        OutputStream out;

        mLogger.i("Downlaod ip = " + SERVER_IP + " port = " + SERVER_PORT);

        try
        {
            socket = new Socket();
            InetSocketAddress socAddress = new InetSocketAddress(SERVER_IP, Integer.parseInt(SERVER_PORT));
            socket.connect(socAddress, 15000);
            socket.setKeepAlive(true);
            in = socket.getInputStream();
            out = socket.getOutputStream();
            // 发送数据：99+8位机器号+1位类型（1：售卖软件 2：远程升级 3：主控）
            // 接收数据：3位数据长度(不包括数据长度本身)+4位版本号+平台类型(2表示x86版,1应该是安卓)+更新地址URL
            mac = getMac("mac.txt");
            if (out != null) {
                out.write(("99" + mac + 2).getBytes());
                out.flush();
            }
            if (in != null) {
                int len = Integer.parseInt(read(in, 3));
                String updateInfo = read(in, len); // 服务器自动返回
                mLogger.i("Downlaod info = " + updateInfo); // Downlaod info = 1ftp://user:111@182.92.226.124/7peizhi.zip
                if ("".endsWith(updateInfo)) {
                    // logger
                    return null;
                }
                int ver = Integer.parseInt(updateInfo.substring(0, 4)); // 服务器上软件的版本
                VERSION = readVersion();
                String curVersion = VERSION; // 当前软件的版本
                int oldVer = 0;
                mLogger.i("Downlaod info: config version is " + curVersion);
                if (curVersion != null) {
                    oldVer = Integer.parseInt(curVersion); // 将当前版本赋给oldVer
                } else {
                    return null;
                }
                if (ver > oldVer) {
                    mLogger.i("update info is : " + updateInfo);
                    return updateInfo;
                } else {
                    mLogger.i("Downlaod info: no new version");
                    return null;
                }
            } else {
                mLogger.i("inputstream is null");
                return null;
            }
        } catch (NumberFormatException e1) {
            mLogger.i("Downlaod NumberFormatException " + e1.getMessage());
            return null;
        } catch (UnknownHostException e1) {
            mLogger.i("Downlaod UnknownHostException " + e1.getMessage());
            return null;
        } catch (IOException e1) {
            mLogger.i("Downlaod IOException " + e1.getMessage());
            return null;
        } finally {
            // 关闭链接
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    mLogger.i("when close occur IOException. " + e.getCause());
                }
            }
        }
    }

    private String readVersion() {
        String version = Configure.getConfigData(Configure.UPDATE_VERSION);
        if(version == null || "".equals(version))
        {
            return "0000";
        }
        return version;
    }

    private String read(InputStream in, int len) throws IOException {
        byte[] buf = new byte[len];
        int readLen = in.read(buf);
        int thisLen;
        if (readLen < len && readLen != -1) {
            while (true) {
                thisLen = in.read(buf, readLen - 1, len - readLen);
                readLen = thisLen + readLen;
                if (readLen >= len)
                    break;
            }
        }
        return new String(buf);
    }

    /**
     * 获取要更新机器的编号
     *
     * @param fileName
     * @return
     */
    private String getMac(String fileName) {

//			String filePath = SDCardUtils.getSDCardPath();
//			filePath = filePath + "/" + fileName;
//			File file = new File(filePath);
//			BufferedReader reader = null;
//			try {
//				reader = new BufferedReader(new InputStreamReader(
//						new FileInputStream(file)));
//
//				return CommUtil.addLeftZero(reader.readLine().trim(), 8);
//			} catch (FileNotFoundException e) {
//				e.printStackTrace();
//			} catch (IOException e) {
//				e.printStackTrace();
//			} finally {
//				if (reader != null) {
//					try {
//						reader.close();
//					} catch (IOException e) {
//						e.printStackTrace();
//					}
//				}
//			}
//			return "00000000";
        return Configure.getMacNo();
    }

    //等待几秒
    private void waitSeconds(final int pSeconds)
    {
        SystemClock.sleep(pSeconds * 1000);
    }

    //检查配置，返回是否开启更新功能
    private boolean loadConfig()
    {
//        File info = new File(PSApplication.CACHEPATH + "/set/config.ini");
//        IniEditor ini = new IniEditor();
//        try {
//            ini.load(info);
//        } catch (IOException e) {
//            mLogger.i("game start load file error");
//            return false;
//        }
//        String useOld = ini.get("updater", "old"); //是否使用老版远程升级，默认是不使用
//        if(useOld != null && (useOld.equals("true") || useOld.equals("1")))
//        {
//            useOldUpdater = true;
//        }
//        String updater = ini.get("updater", "enable");
//        if(updater == null || "".equals(updater))
//        {
//            return true;
//        }
//        if(updater.equals("true") || updater.equals("1"))
//        {
//            return true;
//        }
//        else
//        {
//            return false;
//        }
        return true;
    }
}
